#include "communication_utils.h"

int getsock(void)
{
    FILE *fp = fopen("config.log", "r");
    if (!fp)
    {
        perror("fopen");
        log_init();
        LOG_E("\n\nfopen failed");
        log_destroy();
        return -1;
    }

    int sock, type, port;
    char ip[16];
    if (fscanf(fp, "***********\ntype:%d\nip:%15s\nport:%d\n***********\n", &type, ip, &port) != 3)
    {
        fclose(fp);
        perror("fscanf");
        log_init();
        LOG_E("\n\nfscanf failed");
        log_destroy();
        return -1;
    }
    fclose(fp);
    log_init();
    LOG_E("\ngetsock: type:%d ip:%s port:%d", type, ip, port);
    log_destroy();
    struct sockaddr_in serAddr;
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket");
        log_init();
        LOG_E("\nsocket failed");
        log_destroy();
        return -1;
    }

    memset(&serAddr, 0, sizeof(serAddr));
    serAddr.sin_family = AF_INET;
    serAddr.sin_port = htons(port);
    if (inet_pton(AF_INET, ip, &serAddr.sin_addr) <= 0)
    {
        perror("inet_pton");
        log_init();
        LOG_E("\ninet_pton failed");
        log_destroy();
        close(sock);
        return -1;
    }
    if (type == 1)
    {
        if (connect(sock, (struct sockaddr *)&serAddr, sizeof(serAddr)) == -1)
        {
            perror("connect");
            log_init();
            LOG_E("\nconnect failed");
            log_destroy();
            close(sock);
            return -1;
        }
    }
    else if (type == 2)
    {
        if (bind(sock, (struct sockaddr *)&serAddr, sizeof(serAddr)) == -1)
        {
            perror("bind");
            log_init();
            LOG_E("\nbind failed");
            log_destroy();
            close(sock);
            return -1;
        }
        if (listen(sock, 5) == -1)
        {
            perror("listen");
            log_init();
            LOG_E("\nlisten failed");
            log_destroy();
            close(sock);
            return -1;
        }
    }
    return sock;
}

static int packupjson(message *msg, char *buf)
{
    cJSON *json = cJSON_CreateObject();
    if (!json)
    {
        log_init();
        LOG_E("\ncreate json object failed");
        log_destroy();
        return 0;
    }

    cJSON_AddNumberToObject(json, "O_type", msg->O_type);
    cJSON_AddNumberToObject(json, "D_type", msg->D_type);
    cJSON_AddStringToObject(json, "seforms", msg->seforms);

    char *json_str = cJSON_PrintUnformatted(json);
    if (!json_str)
    {
        log_init();
        LOG_E("\nprint json object failed");
        log_destroy();
        cJSON_Delete(json);
        return 0;
    }

    snprintf(buf, 1024, "%4lu%s", strlen(json_str), json_str);
    cJSON_Delete(json);
    free(json_str);
    return 1;
}

int sendmessage(const int sock, message *msg)
{
    char buf[1024];
    if (!packupjson(msg, buf))
    {
        log_init();
        LOG_E("\npackupjson failed");
        log_destroy();
        return 0;
    }
    log_init();
    LOG_I("\nsendmessage: %s", buf);
    log_destroy();
    if (send(sock, buf, strlen(buf), 0) == -1)
    {
        log_init();
        LOG_E("\nsend failed");
        log_destroy();
        return 0;
    }
    return 1;
}

static int parsejson(char *buf, message *msg)
{
    cJSON *json = cJSON_Parse(buf);
    if (!json)
    {
        perror("Failed to parse JSON");
        log_init();
        LOG_E("\nparsejson failed");
        log_destroy();
        return 0;
    }

    cJSON *item;
    item = cJSON_GetObjectItem(json, "O_type");
    if (item)
        msg->O_type = item->valueint;

    item = cJSON_GetObjectItem(json, "D_type");
    if (item)
        msg->D_type = item->valueint;

    item = cJSON_GetObjectItem(json, "seforms");
    if (item)
        strncpy(msg->seforms, item->valuestring, sizeof(msg->seforms) - 1);

    cJSON_Delete(json);
    return 1;
}

int recvmessage(const int sock, message *msg)
{
    char buf[1024];
    int len = recv(sock, buf, 4, 0);
    if (len == -1)
    {
        strcpy(msg->seforms, "Failed to receive message length");
        return 0;
    }
    int msglen = atoi(buf);
    if (msglen == 0)
    {
        strcpy(msg->seforms, "Message is empty");
        return 0;
    }

    len = recv(sock, buf, msglen, 0);
    if (len == -1)
    {
        strcpy(msg->seforms, "Failed to receive message");
        return 0;
    }
    log_init();
    LOG_I("\nrecvmessage: %s", buf);
    log_destroy();
    if (!parsejson(buf, msg))
    {
        return 0;
    }
    return 1;
}
int senderror(const int sock, const char *errmsg)
{
    message msg;
    memset(&msg, 0, sizeof(msg));
    msg.O_type = error;
    msg.D_type = server;
    strcpy(msg.seforms, errmsg);
    return sendmessage(sock, &msg);
}
int sendresult(const int sock, const char *result)
{
    message msg;
    memset(&msg, 0, sizeof(msg));
    msg.O_type = success;
    msg.D_type = server;
    strcpy(msg.seforms, result);
    return sendmessage(sock, &msg);
}
void sendwarning(struct threadpool *pool, enum Options op)
{
    message msg;
    memset(&msg, 0, sizeof(msg));
    msg.O_type = op;
    int i = 0;
    for (i = 0; i < 1024; i++)
    {
        if (pool->equipment_id[i] > 0)
        {
            sendmessage(i, &msg);
        }
        if (pool->admin_id[i] > 0)
        {
            sendmessage(i, &msg);
        }
    }
}
int sendexit(int sock)
{
    message msg;
    memset(&msg, 0, sizeof(msg));
    msg.O_type = sign_out;
    msg.D_type = server;
    strcpy(msg.seforms, "exit");
    return sendmessage(sock, &msg);
}
int sendata(int sock, const char *data)
{
    message msg;
    memset(&msg, 0, sizeof(msg));
    msg.O_type = senddata;
    msg.D_type = server;
    strcpy(msg.seforms, data);
    return sendmessage(sock, &msg);
}